		TITLE	SEGMINIT - Copyright (c) SLR Systems 1994

		INCLUDE	MACROS
		INCLUDE	IO_STRUC
		INCLUDE	SEGMSYMS
		INCLUDE	EXES


		PUBLIC	SEGM_OUT_INIT


		.DATA

		EXTERNDEF	ZEROS_16:BYTE,TEMP_RECORD:BYTE

		EXTERNDEF	NONRES_BYTES_LEFT:DWORD,OBJ_DEVICE:DWORD,SYMBOL_LENGTH:DWORD,OLD_EXE_HDR_SIZE:DWORD
		EXTERNDEF	CURN_FILE_LIST_GINDEX:DWORD,ENTRYNAME_BITS:DWORD,EXEHDR_ADDR:DWORD,OS2_EXEHDR_START:DWORD

		EXTERNDEF	OLD_LIST:FILE_LISTS,ENTRYNAME_STUFF:ALLOCS_STRUCT,EXEHEADER:EXE,OLD_LIST:FILE_LISTS
		EXTERNDEF	STUB_LIST:FILE_LISTS,_FILE_LIST_GARRAY:STD_PTR_S

		EXTERNDEF	OPTI_MOVE:DWORD


		.CODE	PASS2_TEXT

		EXTERNDEF	_n_res_table:proc
		EXTERNDEF	_open_reading:proc,_n_nonres_table:PROC,SEARCH_ENTRYNAME:PROC,_close_myi_handle:proc
		EXTERNDEF	_release_myi_ptr:proc,RELEASE_IO_SEGMENT:PROC,ERR_ABORT:PROC,MOVE_EXEHDR_TO_FINAL:PROC,DOT:PROC
		EXTERNDEF	OPTI_MOVE_PRESERVE_SIGNIFICANT:PROC,REPORT_CLOSE_ASCIZ:PROC

		EXTERNDEF	BAD_STUB_ERR:ABS


SEGM_OUT_INIT	PROC
		;
		;OPEN EXE OR COM FILE FOR OUTPUT
		;
		;
		;NEED TO OUTPUT EITHER THE STANDARD STUB OR THE SUPPLIED ONE
		;
		XOR	EAX,EAX

		MOV	EXEHDR_ADDR,EAX		;NEXT EXEHDR WRITE ADDRESS

		BITT	STUB_SUPPLIED
		JNZ	L5$
		BITT	STUB_NONE		;NO STUB AT ALL...
		JNZ	L8$
		;
		;THIS IS THE EASY METHOD...
		;
L59$:
		MOV	EAX,OFF DFLT_STUB	;MOVE DEFAULT STUB
		MOV	ECX,DFLT_STUB_LEN
if	fg_pe
		BITT	OUTPUT_PE
		JZ	L591$

		MOV	EAX,OFF DFLT_NT_STUB
L591$:
endif
		CALL	MOVE_EXEHDR_TO_FINAL
L8$:
		MOV	EAX,EXEHDR_ADDR
		MOV	OS2_EXEHDR_START,EAX	;DEFINE OS2 HEADER START ADDRESS

		MOV	CURN_FILE_LIST_GINDEX,0	;FOR ERRORS...

		RET

L5$:
		;
		;OK, NEED TO COPY A SPECIFIC STUB TO OUTPUT STREAM
		;
		MOV	EAX,STUB_LIST.FILE_FIRST_GINDEX
		CONVERT	EAX,EAX,_FILE_LIST_GARRAY
		ASSUME	EAX:PTR FILE_LIST_STRUCT

		MOV	EAX,[EAX].FILE_LIST_NEXT_GINDEX
		push	EAX
		call	_open_reading		;GET OPEN STUB FILE...
		add	ESP,4
		test	EAX,EAX
		stc
		jz	L59$			;not found

		ASSUME	EAX:PTR MYI_STRUCT
		;
		;NOW GET FIRST BLOCK OF DATA...
		;
		push	EAX
		CALL	[EAX].MYI_FILLBUF
		add	ESP,4

		MOV	ESI,[EAX].MYI_PTRA
		ASSUME	ESI:PTR EXE
		;
		;DS:SI IS EXEHEADER...
		;
		MOV	EDI,OFF EXEHEADER		;VERIFY SIGNATURE
		ASSUME	EDI:PTR EXE

		CMP	[ESI]._EXE_SIGN,'ZM'
		JNZ	L9$		;NOT VALID EXE...
		;
		;SAVE A COPY OF OLD HEADER
		;
		MOVZX	EAX,[ESI]._EXE_LEN_PAGE_512	;CONVERT SIZE INTO FLAT 32-BIT #
		MOVZX	ECX,[ESI]._EXE_LEN_MOD_512

		SHL	EAX,9

		TEST	ECX,ECX
		JZ	L51$

		LEA	EAX,[EAX+ECX-512]
L51$:
		MOV	DPTR [EDI]._EXE_LEN_MOD_512,EAX	;STORE AS 32-BIT #
		;
		;SUBTRACT OUT HEADER SIZE...
		;
		MOVZX	EAX,[ESI]._EXE_HDR_SIZE		;IN PARAGRAPHS

		MOV	OLD_EXE_HDR_SIZE,EAX

		SHL	EAX,4

		SUB	DPTR [EDI]._EXE_LEN_MOD_512,EAX	;RESULTS IN LOAD IMAGE SIZE?
		;
		;CALC NEW HEADER SIZE...
		;
		MOVZX	EAX,[ESI]._EXE_N_RELOC

		MOV	[EDI]._EXE_N_RELOC,AX
		ADD	EAX,3

		SHR	EAX,2				;# OF PARAGRAPHS USED BY RELOCS

		ADD	EAX,4				;OTHER HEADER PARAGRAPHS

		MOV	[EDI]._EXE_HDR_SIZE,AX		;HEADER SIZE IN PARAS

		SHL	EAX,4				;HEADER SIZE IN BYTES

		ADD	EAX,DPTR [EDI]._EXE_LEN_MOD_512	;OVERALL SIZE IN BYTES

		MOV	ECX,EAX
		AND	EAX,511

		MOV	[EDI]._EXE_LEN_MOD_512,AX	;SIZE MOD 512
		ADD	ECX,511

		SHR	ECX,9
		MOV	EBX,ESI

		MOV	[EDI]._EXE_LEN_PAGE_512,CX	;# OF 512-BYTE PAGES
		LEA	EDI,[EDI]._EXE_MIN_ABOVE
		ASSUME	EDI:NOTHING

		LEA	ESI,[ESI]._EXE_MIN_ABOVE		;PRESERVE HEADER UP TO RELOC_OFF
		MOV	ECX,(EXE._EXE_RELOC_OFF-EXE._EXE_MIN_ABOVE)/2
		ASSUME	ESI:NOTHING

		REP	MOVSW

		MOV	EAX,40H				;NEW RELOC_OFF IS 40H
		STOSW
		LODSW
		;
		;MOVE UP TO RELOC_OFF OR 003C, WHICHEVER IS SMALLER
		;
		MOVSW			;OVERLAY #

		SUB	EAX,ESI
		MOV	ECX,3CH-EXE._EXE_OVLY_NUM-2

		ADD	EAX,EBX		;BYTES TILL RELOC_OFF

		CMP	ECX,EAX
		JB	L52$

		XCHG	EAX,ECX
L52$:
		REP	MOVSB
		;
		;FILL TO 003C WITH ZEROS
		;
		MOV	ECX,OFF EXEHEADER+3CH
		SUB	ECX,EDI
		XOR	EAX,EAX

		REP	STOSB
		;
		;STORE A 16-BYTE BOUNDARY AS OS2EXE OFFSET...
		;
		MOV	ECX,OBJ_DEVICE
		ASSUME	ECX:PTR MYI_STRUCT

		MOV	EAX,[ECX].MYI_FILE_LIST_GINDEX
		CONVERT	EAX,EAX,_FILE_LIST_GARRAY
		ASSUME	EAX:PTR FILE_LIST_STRUCT

		MOV	ECX,[EAX].FILE_LIST_NFN.NFN_FILE_LENGTH
		;
		;ADD IN ADJUSTMENT FOR CHANGE IN HEADER SIZE...
		;
		MOV	EAX,OLD_EXE_HDR_SIZE

		MOVZX	EDX,EXEHEADER._EXE_HDR_SIZE

		SUB	EAX,EDX

		SHL	EAX,4

		SUB	ECX,EAX

		XCHG	EAX,ECX
		;
		ADD	EAX,15

		AND	AL,0F0H

		STOSD
		;
		;NOW WRITE 40H BYTES FROM EXEHEADER
		;
		MOV	EAX,OFF EXEHEADER
		MOV	ECX,40H

		CALL	MOVE_EXEHDR_TO_FINAL
		;
		;NOW MOVE ANY AND ALL RELOCATIONS
		;
		MOV	EAX,OBJ_DEVICE
		ASSUME	EAX:PTR MYI_STRUCT

		MOV	ECX,[EAX].MYI_COUNT
		MOV	ESI,[EAX].MYI_PTRA
		ASSUME	ESI:PTR EXE

		MOVZX	EAX,[ESI]._EXE_N_RELOC

		MOVZX	EBX,[ESI]._EXE_RELOC_OFF

		ADD	ESI,EBX
		SUB	ECX,EBX
		ASSUME	ESI:NOTHING

		JC	L9$

		SHL	EAX,2		 	;EAX IS # OF BYTES TO MOVE...
		CALL	MOVE_BUNCH

		PUSH	ECX
		CALL	PARA_OUTPUT		;ROUND OUTPUT TO PARAGRAPH
		;
		;NOW MOVE REST OF EXE (INCLUDING OVERLAYS, CV INFO, ETC.)
		;
		POP	ECX
		MOV	EAX,OLD_EXE_HDR_SIZE

		SHL	EAX,4			;BYTES IN HEADER
		MOV	EDX,OBJ_DEVICE
		ASSUME	EDX:PTR MYI_STRUCT

		MOV	EBX,EAX
		AND	EAX,PAGE_SIZE-1		;DESIRED OFFSET IN BLOCK

		SUB	EAX,ESI			;CURRENT OFFSET IN BLOCK

		ADD	EAX,[EDX].MYI_PTRA

		SUB	ECX,EAX
		JC	L9$

		ADD	ESI,EAX
		;
		MOV	EDX,[EDX].MYI_FILE_LIST_GINDEX

		CONVERT	EDX,EDX,_FILE_LIST_GARRAY
		ASSUME	EDX:PTR FILE_LIST_STRUCT

		MOV	EAX,[EDX].FILE_LIST_NFN.NFN_FILE_LENGTH
		MOV	EDX,OLD_EXE_HDR_SIZE

		SHL	EDX,4

		SUB	EAX,EDX
		CALL	MOVE_BUNCH

		MOV	EBX,OBJ_DEVICE
		ASSUME	EBX:PTR MYI_STRUCT

		XOR	ECX,ECX
		MOV	EAX,[EBX].MYI_BLOCK

		MOV	[EBX].MYI_BLOCK,ECX
		MOV	[EBX].MYI_PTRA,ECX

		CALL	RELEASE_IO_SEGMENT

		CALL	PARA_OUTPUT

if	fgh_inthreads
		BITT	_HOST_THREADED
		JNZ	L7$
endif
		MOV	EAX,EBX

	push	EAX
	call	_close_myi_handle
	add	ESP,4

L7$:
if	fgh_win32dll
;		CALL	REPORT_CLOSE_ASCIZ
endif
		;
		;OK, THAT SHOULD DO IT...
		;
		JMP	L8$

L9$:
		MOV	AX,BAD_STUB_ERR
		CALL	ERR_ABORT


SEGM_OUT_INIT	ENDP


MOVE_BUNCH	PROC	NEAR	PRIVATE
		;
		;ESI IS DATA SOURCE, ECX IS BYTES LEFT THIS BLOCK
		;EAX IS # OF BYTES TO MOVE
		;
		JMP	MB_3

MB_LT64:
		CALL	MB_GNB		;DS:SI IS POINTER, CX IS COUNT
MB_3:
		;
		;ECX IS BYTES LEFT THIS BLOCK
		;EAX IS TOTAL # OF BYTES TO MOVE
		;
		;MOVE SMALLER OF EAX AND ECX
		;
		MOV	EDX,ECX		;# IN BLOCK
		CMP	ECX,EAX
		JB	MB_4
		MOV	ECX,EAX
MB_4:
		CALL	MB_MOVE_CX_FLUSH

		SUB	EAX,ECX
		JNZ	MB_LT64

		SUB	EDX,ECX
		ADD	ESI,ECX

		MOV	ECX,EDX
		;
		RET

MOVE_BUNCH	ENDP


MB_GNB		PROC	NEAR
		;
		;GET NEXT BUFFER
		;
		PUSHM	EDX,EAX

		MOV	EAX,OBJ_DEVICE
		ASSUME	EAX:PTR MYI_STRUCT

		push	EAX
		CALL	[EAX].MYI_FILLBUF
		add	ESP,4

		MOV	ECX,[EAX].MYI_COUNT
		MOV	ESI,[EAX].MYI_PTRA

		POPM	EAX,EDX

		RET

MB_GNB		ENDP


MB_MOVE_CX_FLUSH	PROC	NEAR
		;
		;
		;
		PUSHM	EDX,EAX,ECX

		MOV	EAX,ESI
		CALL	MOVE_EXEHDR_TO_FINAL		;STORE THAT MUCH

		POPM	ECX,EAX,EDX
		
		RET

MB_MOVE_CX_FLUSH	ENDP


PARA_OUTPUT	PROC	NEAR
		;
		;ROUND HEADER OUTPUT TO PARAGRAPH BOUNDARY
		;
		XOR	EAX,EAX
		SUB	EAX,EXEHDR_ADDR

		AND	EAX,0FH
		JZ	L9$

		MOV	ECX,EAX
		MOV	EAX,OFF ZEROS_16

		JMP	MOVE_EXEHDR_TO_FINAL

L9$:
		RET

PARA_OUTPUT	ENDP


		PUBLIC	PROCESS_OLD


PROCESS_OLD	PROC
		;
		;AN 'OLD' FILE WAS GIVEN..., NOW WHAT?
		;
		;FIRST, WERE ANY EXPORTS DECLARED?
		;
		CMP	ENTRYNAME_STUFF.ALLO_HASH_TABLE_PTR,0
		JZ	L9$		;NOPE, SKIP IT...
		;
		;OK, SET UP TO OPEN AND READ FROM OLD FILE
		;
		MOV	EAX,OLD_LIST.FILE_FIRST_GINDEX
		CONVERT	EAX,EAX,_FILE_LIST_GARRAY
		ASSUME	EAX:PTR FILE_LIST_STRUCT

		MOV	EAX,[EAX].FILE_LIST_NEXT_GINDEX
		push	EAX
		call	_open_reading		;GET OPEN OLD FILE...
		add	ESP,4

		test	EAX,EAX
		stc
		jz	L9$

		push	EAX
		call	_n_res_table
		add	ESP,4

		TEST	EAX,EAX
		JZ	L5$

		CALL	PROCESS_THIS_SET
L5$:
		;
		;NOW, GET # OF BYTES IN NONRESIDENT NAME TABLE
		;
		push	EAX
		call	_n_nonres_table		;0 IF ERROR OR NONE...
		add	ESP,4

		TEST	EAX,EAX
		JZ	L8$

		CALL	PROCESS_THIS_SET
L8$:
		;
		;RELEASE BLOCK AT MYI_PTR IF THERE
		;
	push	EAX
	call	_release_myi_ptr
	add	ESP,4
ife	fgh_inthreads
	push	EAX
	call	_close_myi_handle
	add	ESP,4
endif

L9$:
		MOV	CURN_FILE_LIST_GINDEX,0	;FOR ERRORS...

		RET

PROCESS_OLD	ENDP


PROCESS_THIS_SET	PROC	NEAR
		;
		;
		;
		MOV	NONRES_BYTES_LEFT,EAX
		MOV	EAX,OBJ_DEVICE
		ASSUME	EAX:PTR MYI_STRUCT

		push	EAX
		CALL	[EAX].MYI_FILLBUF	;GET DATA
		add	ESP,4
if	fgh_inthreads
		MOV	[EAX].MYI_BUFCNT,0
endif

L3$:
		CALL	GET_NEXT_NAME		;DS:SI POINTS TO NEXT

		MOV	ECX,0
		JC	L9$			;DX IS HASH, SYMBOL_DATA

		MOV	CX,[ESI] 		;ENTRY #
		MOV	ESI,ENTRYNAME_BITS
		;
		;FIRST SEE IF IT IS USED UP...
		;
		TEST	ECX,ECX
		JZ	L3$			;ORD 0 IS DESCRIPTION...

		PUSH	ECX
		MOV	EBX,ECX

		SHR	EBX,3		;THAT BYTE
		AND	ECX,7

		MOV	EAX,1

		SHL	AL,CL		;THAT BIT...

		MOV	AH,BYTE PTR[ESI+EBX]
		POP	ECX

		TEST	AH,AL
		JNZ	L3$		;ORD ALREADY DEFINED
		;
		;SEE IF THAT EXPORT EXISTS
		;
		PUSH	ECX
		CALL	SEARCH_ENTRYNAME	;
		ASSUME	ECX:PTR ENT_STRUCT

		POP	EDX
		JC	L3$		;NOT AN EXPORT ANY MORE

		MOV	EAX,[ECX]._ENT_ORD

		CMP	EAX,EDX
		JZ	L3$

		TEST	EAX,EAX
		JNZ	L3$

		MOV	[ECX]._ENT_ORD,EDX
		MOV	EBX,EDX

		SHRI	EBX,3		;THAT BYTE
		MOV	ECX,EDX

		AND	ECX,7
		MOV	EAX,1

		SHL	AL,CL		;THAT BIT...

		OR	BYTE PTR[ESI+EBX],AL
		JMP	L3$

L9$:
		RET

PROCESS_THIS_SET	ENDP


GET_NEXT_NAME	PROC	NEAR
		;
		;CARRY MEANS FINISHED
		;RETURN DS:SI AT END OF TEXT (PTING TO ORD #)
		;DX IS HASH, SYMBOL_LENGTH IS SYMBOL
		;
		PUSH	EBX
		MOV	EBX,OBJ_DEVICE
		ASSUME	EBX:PTR MYI_STRUCT

		MOV	EAX,1
		CALL	GNN		;RETURN PTR TO ONE BYTE

		PUSH	EDI
		JC	L9$

		MOV	EDI,OFF SYMBOL_LENGTH
		MOV	AL,[ESI]

		INC	ESI
		AND	EAX,0FFH

		MOV	[EDI],EAX
		ADD	EDI,4

		TEST	EAX,EAX
		JZ	L9$		;ZERO LENGTH IS END OF TABLE

		PUSH	EAX
		CALL	GNN		;RETURN PTR TO AX BYTES

		POP	EAX
		JC	L9$

		CALL	OPTI_MOVE_PRESERVE_SIGNIFICANT	;HASHED

		POP	EDI
		PUSH	EDX

		MOV	EAX,2		;PTR TO ORD #
		CALL	GNN

		POPM	EDX,EBX

		RET

L9$:
		;
		;TABLE IS DONE...
		;
		CMP	ESP,-1
		POP	EDI

		POP	EBX

		RET

GET_NEXT_NAME	ENDP


GNN		PROC	NEAR
		;
		;RETURN PTR TO EAX BYTES
		;EBX IS MYI_STRUCT
		;
		MOV	ECX,NONRES_BYTES_LEFT
		MOV	EDX,[EBX].MYI_COUNT

		SUB	ECX,EAX
		JC	L9$

		SUB	EDX,EAX
		JC	L1$

		MOV	ESI,[EBX].MYI_PTRA
		MOV	NONRES_BYTES_LEFT,ECX

		ADD	EAX,ESI
		MOV	[EBX].MYI_COUNT,EDX

		MOV	[EBX].MYI_PTRA,EAX
L9$:
		RET

L1$:
		PUSH	EDI
		MOV	NONRES_BYTES_LEFT,ECX

		MOV	ECX,[EBX].MYI_COUNT
		MOV	EDI,OFF TEMP_RECORD

		SUB	EAX,ECX		;NUMBER TO MOVE AFTER THE FACT
		MOV	ESI,[EBX].MYI_PTRA

		OPTI_MOVSB

		PUSH	EAX
		MOV	EAX,EBX

		push	EAX
		CALL	[EBX].MYI_FILLBUF
		add	ESP,4

if	fgh_inthreads
		MOV	[EBX].MYI_BUFCNT,0
endif
		POP	ECX
		MOV	ESI,[EBX].MYI_PTRA

		SUB	[EBX].MYI_COUNT,ECX
		JC	L8$

		OPTI_MOVSB

		MOV	[EBX].MYI_PTRA,ESI
		POP	EDI

		MOV	ESI,OFF TEMP_RECORD
		CMP	AL,AL

		RET

L8$:
		CMP	ESP,-1
		POP	EDI

		RET

GNN		ENDP


		.CONST

		ALIGN	4

DFLT_STUB	DW	'ZM',DFLT_STUB_LEN,1,0,4,10H,-1,0
		DW	00FEH,0,12H,0,40H,0,0,0
		DW	0,0,0,0,0,0,0,0
		DW	0,0,0,0,0,0,DFLT_STUB_LEN,0
		DB	'Not a DOS Progra'
		DB	'm$',16H,1FH,33H,0D2H,0B4H,9
		DB	0CDH,21H,0B8H,01,4CH,0CDH,21H,0

DFLT_STUB_LEN	EQU	$-DFLT_STUB


		ALIGN	4

DFLT_NT_STUB	DW	'ZM',DFLT_NT_STUB_LEN,1,0,4,10H,-1,0
		DW	00FEH,0,12H,0,40H,0,0,0
		DW	0,0,0,0,0,0,0,0
		DW	0,0,0,0,0,0,DFLT_NT_STUB_LEN,0
		DB	'Requires Win32  '
		DB	' $',16H,1FH,33H,0D2H,0B4H,9
		DB	0CDH,21H,0B8H,01,4CH,0CDH,21H,0

DFLT_NT_STUB_LEN	EQU	$-DFLT_NT_STUB


		END

